package cn.yuanqiao.archive.webservice.service.impl;

import cn.yuanqiao.archive.appManager.domain.*;
import cn.yuanqiao.archive.appManager.mapper.*;
import cn.yuanqiao.archive.danganzhengli.domain.YqdaOnlineReception;
import cn.yuanqiao.archive.danganzhengli.service.IOnlineReceptionService;
import cn.yuanqiao.archive.uploadfile.service.impl.FileService;
import cn.yuanqiao.archive.webservice.service.ArchiveEnhanceService;
import cn.yuanqiao.archive.webservice.service.ArchiveWebService;
import cn.yuanqiao.archive.webservice.utils.WebServiceFileUtils;
import cn.yuanqiao.archive.webservice.utils.XMLtoJsonUtils;
import cn.yuanqiao.archive.wenjianzhengli.utils.FileUploadUtils;
import cn.yuanqiao.common.core.domain.BusinessActivity;
import cn.yuanqiao.common.exception.ServiceException;
import cn.yuanqiao.common.utils.DateUtils;
import cn.yuanqiao.common.utils.SnowflakeIdGenerator;
import cn.yuanqiao.common.utils.StringUtils;
import cn.yuanqiao.feignService.AsyncLogService;
import cn.yuanqiao.manage.domain.ManageTenant;
import cn.yuanqiao.manage.service.IManageTenantService;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.Base64Utils;

import javax.jws.WebService;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@WebService(serviceName  = "saveArchive",    // 与接口中的name相同
        targetNamespace = "http://service.webservice.archive.yuanqiao.cn",  // 一般为当前包名的倒序
        endpointInterface = "cn.yuanqiao.archive.webservice.service.ArchiveWebService"  // 为接口类的包名
)
public class ArchiveWebServiceImpl implements ArchiveWebService {
    private final Logger logger = LoggerFactory.getLogger(ArchiveWebServiceImpl.class);
    @Value("${onLineArchive.Path}")
    private String onLineArchivePath;
    @Value("${onLineArchive.Charset}")
    private String onLineArchiveCharset;
    @Autowired
    private TenantCategoryMapper tenantCategoryMapper;
    @Autowired
    private TenantMdataListMapper tenantMdataListMapper;
    @Autowired
    private TenantYqdaMapper tenantYqdaMapper;
    @Autowired
    private TenantYqdaDocumentMapper tenantYqdaDocumentMapper;
    @Autowired
    private TenantSysDictDataMapper tenantSysDictDataMapper;
    @Autowired
    private TenantSysConfigMapper tenantSysConfigMapper;
    @Autowired
    private AsyncLogService asyncLogService;
    @Autowired
    private ArchiveMapper archiveMapper;
    @Autowired
    private IOnlineReceptionService onlineReceptionService;
    @Autowired
    private IManageTenantService manageService;
    @Autowired
    private ArchiveEnhanceService archiveEnhanceService;

    private static DateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    @Transactional
    public String saveArchive(String archiveCode,String fileMD5,String data) {
        JSONObject msg = new JSONObject();
        msg.put("code",500);
        try {
            logger.info("archiveCode={}",archiveCode);
            String archive = new String(Base64Utils.decodeFromString(archiveCode));
            logger.info("archive={}",archive);//{"categoryId":"123456789","tenantCode":"A001"}
            logger.info("fileMD5={}",fileMD5);
            //String onLineArchivePath = sysConfigService.selectConfigByKey("onLineArchivePath");
            //String onLineArchiveCharset = sysConfigService.selectConfigByKey("onLineArchiveCharset");
            if(StringUtils.isNotEmpty(onLineArchivePath)){
                JSONObject info = JSONObject.parseObject(archive);
                String path = onLineArchivePath+fileMD5+".zip";  //归档包保存路径
                logger.info("path={}",path);
                WebServiceFileUtils.base64ToFile(data,new File(path));  //base64转文件
                String md5 = WebServiceFileUtils.getFileMD5(new File(path));  //获取文件MD5
                if(fileMD5.equals(md5)){
                    onLineArchiveCharset = StringUtils.isNotEmpty(onLineArchiveCharset) ? onLineArchiveCharset:"UTF-8";  //解压文件编码
                    logger.info("onLineArchiveCharset={}",onLineArchiveCharset);
                    String unzipPath = onLineArchivePath+fileMD5;   //解压文件路径
                    logger.info("unzipPath={}",unzipPath);
                    FileService.decompress(path,unzipPath,onLineArchiveCharset);  //解压文件
                    traverseFiles(new File((unzipPath)),info,msg);  //遍历文件
                    FileUtils.deleteQuietly(new File(unzipPath));//删除文件
                    msg.put("code",200);
                }else {
                    msg.put("code",502);
                    msg.put("msg","文件MD5值不一致！");
                    //logger.error("文件MD5值不一致！");
                    //throw new ServiceException("文件MD5值不一致");
                }
            }else {
                msg.put("code",501);
                throw new ServiceException("在线移交包路径未配置");
                //logger.error("在线移交包路径未配置！");
            }
        }catch (Exception e){
            logger.error(e.getMessage(),e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动回滚事务
            if(e instanceof ServiceException && e.getMessage().indexOf("文件获取失败")>-1){
                msg.put("code",503);
                msg.put("msg","缺少电子文件！");
            }
        }
        logger.info("return={}",msg.toJSONString());
        return msg.toJSONString();
    }

    /**
     * 遍历文件
     * @param directory
     * @param info
     * @param msg
     * @throws Exception
     */
    private void traverseFiles(File directory, JSONObject info, JSONObject msg) throws Exception {
        if (directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    traverseFiles(file,info,msg);
                }
            }
        } else {
            //文件类型
            if(directory.getName().toLowerCase().endsWith(".xml")&&!"目录信息.xml".equals(directory.getName())) {
                Long daId = analysisArchive(directory,info,msg);
            }
        }
    }

    /**
     * 解析数据
     * @param xmlFile
     * @param info
     * @param msg
     * @throws Exception
     */
    private Long analysisArchive(File xmlFile, JSONObject info, JSONObject msg) throws Exception{
        JSONObject archiveData = XMLtoJsonUtils.startXMLToJSON(xmlFile);  //xml 文件解析成 JSON格式
        logger.info("sssssssssssssssssssssss:"+archiveData.toJSONString());
        Long categoryId = info.getLong("categoryId");
        String tenantCode = info.getString("tenantCode");
        TenantCategory category = tenantCategoryMapper.selectTenantCategoryByID(categoryId,tenantCode+ TenantCategory.BIGTABLENAME);
        logger.info(category.toString());
        TenantMdataList selectMdtaList = new TenantMdataList();
        selectMdtaList.setGroupId(category.getGroupId());
        selectMdtaList.setType(0);//只保存件层
        selectMdtaList.setTableName(tenantCode+ TenantMdataList.BIGTABLENAME);
        List<TenantMdataList> mdataLists = tenantMdataListMapper.selectTenantMdataListList(selectMdtaList);
        Map<String,String> colData = new HashMap<>();
        JSONObject archiveInfo = archiveData.getJSONObject("文件目录");
        for(TenantMdataList mdataList:mdataLists){  //循环电子文件层元数据方案
            if(archiveInfo.containsKey(mdataList.getFieldCaption())){  //判断是否存在
                colData.put(mdataList.getFieldName(),archiveInfo.getString(mdataList.getFieldCaption()));   //先赋值
                if(mdataList.getShowType() == 5){  //字典类型处理
                    List<TenantSysDictData> dictDatas = tenantSysDictDataMapper.selectDictDataByType(mdataList.getFieldName(),tenantCode+ TenantSysDictData.BIGTABLENAME);
                    for(TenantSysDictData sysDictData:dictDatas){
                        if(sysDictData.getDictLabel().equals(archiveInfo.getString(mdataList.getFieldCaption()))){
                            colData.put(mdataList.getFieldName(),sysDictData.getDictValue());  //字典项值覆盖
                            break;
                        }
                    }
                }else if(mdataList.getShowType() == 1){
                    if(archiveInfo.getString(mdataList.getFieldCaption()) == null || "".equals(archiveInfo.getString(mdataList.getFieldCaption()).trim())){
                        //colData.put(mdataList.getFieldName(),"0");
                        colData.remove(mdataList.getFieldName());
                    }
                }/*else if(mdataList.getShowType() == 7){
                    if(StringUtils.isNotNull(archiveInfo.getLong(mdataList.getFieldCaption()))){
                        String deptId = archiveMapper.getDeptIdByName(archiveInfo.getString(mdataList.getFieldCaption())));

                    }
                }*/
                if((mdataList.getFieldName().equals("GDSJ_ID") || mdataList.getFieldName().equals("GDCS_ID")) && StringUtils.isNotEmpty(archiveInfo.getString(mdataList.getFieldCaption()))){
                    Long deptId = archiveMapper.getDeptIdByOneId(archiveInfo.getString(mdataList.getFieldCaption()),tenantCode);
                    if(deptId !=null){
                        colData.put(mdataList.getFieldName(), String.valueOf(deptId));
                    }
                }
                if(mdataList.getFieldName().equals("JBR_ID") && StringUtils.isNotEmpty(archiveInfo.getString(mdataList.getFieldCaption()))){
                    Long deptId = archiveMapper.getDeptIdByOneId(archiveInfo.getString(mdataList.getFieldCaption()),tenantCode);
                    if(deptId !=null){
                        colData.put(mdataList.getFieldName(), String.valueOf(deptId));
                    }
                }
            }
        }
        //必须内容处理
        Long daId = SnowflakeIdGenerator.generateId();
        colData.put("ID",String.valueOf(daId));
        colData.put("IS_DEL","0");
        colData.put("IS_INDEX","0");
        colData.put("STATE","1");
        colData.put("TYPE",category.getCode());
        colData.put("QZH",category.getFondsCode());
        colData.put("JS_TYPE","1");  //在线移交
        TenantYqda yqda = new TenantYqda();
        yqda.setColNames(colData);
        yqda.setTableName(category.getFileTableName());
        logger.info(JSONObject.toJSONString(colData.toString()));
        tenantYqdaMapper.insertYqdaDisperse(yqda);
        colData.put("SUB_TABLE_NAME",category.getFileTableName());
        yqda.setTableName(tenantCode+ TenantYqda.BIGTABLENAME);
        colData.remove("ID");
        colData.put("DA_ID",String.valueOf(daId));
        tenantYqdaMapper.insertYqda(yqda);
        //解析电子文件
        int efileCount = saveEFile(xmlFile,archiveData,msg,daId,category,tenantCode);
        //更新电子文件数量
        tenantYqdaMapper.updateYqdaOneColumn(tenantCode+ TenantYqda.BIGTABLENAME,"EFILE_COUNT",String.valueOf(efileCount),daId);
        tenantYqdaMapper.updateYqdaOneColumnDisperse(category.getFileTableName(),"EFILE_COUNT",String.valueOf(efileCount),daId);
        //解析过程信息
        analysisProcessInfo(archiveData,daId,tenantCode);
        return daId;
    }

    private int saveEFile(File xmlFile, JSONObject archiveData, JSONObject msg, Long daId, TenantCategory category, String tenantCode) throws Exception{
        int r = 0;
        Object o = archiveData.getJSONObject("电子属性集").get("电子属性");
        JSONArray efileJson = new JSONArray();
        if(o instanceof JSONObject){
            efileJson.add(o);
        }else if(o instanceof JSONArray){
            efileJson = (JSONArray)o;
        }
        //TenantMdataList selectMdtaList = new TenantMdataList();
        //selectMdtaList.setGroupId(category.getGroupId());
        //selectMdtaList.setType(2);//电子文件层
        //List<TenantMdataList> mdataLists = tenantMdataListMapper.selectTenantMdataListList(selectMdtaList);
        String dictType = "TYPE"; //文件类型
        List<TenantSysDictData> dictDatas = tenantSysDictDataMapper.selectDictDataByType(dictType,tenantCode+ TenantSysDictData.BIGTABLENAME);
        TenantSysConfig config = new TenantSysConfig();
        config.setTenantCode(tenantCode);
        config.setConfigKey("YQ_MNT");
        String baseDir = tenantSysConfigMapper.selectConfig(config).getConfigValue();  //保存位置
        for(int i = 0;i<efileJson.size();i++){
            JSONObject efileData = efileJson.getJSONObject(i);
            //格式信息
            String docFileType = efileData.getString("格式信息").replace(".","").toUpperCase();
            String docName =  efileData.getString("计算机文件名");
            String docFileSize = efileData.getString("计算机文件大小");
            String typeStr = efileData.getString("文件类型");
            String showName = efileData.getString("文件名称");
            String type = "1";
            for(TenantSysDictData sysDictData:dictDatas){  //处理类型
                if(sysDictData.getDictLabel().equals(typeStr)){
                    type = sysDictData.getDictValue();
                    break;
                }
            }
            TenantYqdaDocument document = new TenantYqdaDocument();
            document.setConTableId(daId);
            document.setTableName(category.getEfileTableName());
            String orderNoStr = tenantYqdaDocumentMapper.MaxOrderNo(document);
            int orderNo =  StringUtils.isEmpty(orderNoStr) ? 1:(Integer.valueOf(orderNoStr)+1); //文件顺序
            String fileName = extractFilename(type,daId,orderNo,docFileType);  //保存文件名
            File xmlPath = new File(xmlFile.getParent()+File.separator+docName);  //归档包电子文件路径
            if(!xmlPath.exists()){
                logger.error(xmlPath.getAbsolutePath()+xmlPath.getName());
                throw new ServiceException(docName+"。文件获取失败！");
            }
            String filePath = extractPath(category,daId);  //存储的相对路径
            String absPath = getAbsoluteFile(baseDir+filePath, fileName).getAbsolutePath();  //保存文件位置  绝对路径
            FileUtils.copyFile(xmlPath,new File(absPath));  //复制文件
            // 获取文件属性
            BasicFileAttributes attributes = Files.readAttributes(Paths.get(absPath), BasicFileAttributes.class);
            // 获取文件创建时间
            FileTime createTime = attributes.creationTime();
            // 将文件创建时间转换为标准格式
            String dateFormat = df.format(createTime.toMillis());
            TenantYqdaDocument saveDocument = new TenantYqdaDocument();
            Map<String,String> colNum = new HashMap<>();
            colNum.put("PATH",filePath+fileName);
            colNum.put("DOC_ORDER", String.valueOf(orderNo));
            colNum.put("DOC_NAME",showName);
            colNum.put("DOC_FILE_TYPE", docFileType.toUpperCase());
            colNum.put("IS_DEL","0");
            colNum.put("ACTION_TIME",dateFormat);
            colNum.put("CREATE_TIME", DateUtils.getTime());
            colNum.put("DOC_FILE_SIZE",docFileSize);
            colNum.put("IS_INDEX","0");
            colNum.put("TYPE",type);
            colNum.put("REAL_DOC_NAME",fileName);
            colNum.put("DOC_MNT",baseDir);
            colNum.put("DOC_CREATE_TIME", FileUploadUtils.getDocCreateTime(new File(absPath)));
            saveDocument.setColNames(colNum);
            saveDocument.setTableName(category.getEfileTableName());
            saveDocument.setDocId(SnowflakeIdGenerator.generateId());
            saveDocument.setConTableId(daId);
            r = r + tenantYqdaDocumentMapper.insertDocument(saveDocument);
        }
        return r;
    }

    private void analysisProcessInfo(JSONObject archiveData, Long daId, String tenantCode) throws Exception{
        if(archiveData.getJSONObject("过程信息集") !=null){
            Object processInfo = archiveData.getJSONObject("过程信息集").get("过程信息");
            JSONArray processArray = new JSONArray();
            if(processInfo instanceof JSONObject){
                processArray.add(processInfo);
            }else if(processInfo instanceof JSONArray){
                processArray = (JSONArray)processInfo;
            }
            for(int i = 0;i<processArray.size();i++){
                JSONObject object = processArray.getJSONObject(i);
                String name = object.getString("处理类型");
                //BusinessBehavior businessBehavior = BusinessBehavior.valueOf(name, 0);
                BusinessActivity businessActivity = new BusinessActivity();
                businessActivity.setCode(-1);
                businessActivity.setName(name);
                businessActivity.setUserName(object.getString("处理人员"));
                Date date = null;
                if(StringUtils.isNotEmpty(object.getString("处理时间"))){
                    date = object.getDate("处理时间");
                }
                businessActivity.setActionTime(date);
                businessActivity.setDept(object.getString("处理部门"));
                businessActivity.setDaId(daId);
                //businessActivity.setUserId(sysUser.getUserId());
                //businessActivity.setDeptId(sysUser.getDept().getDeptId());
                businessActivity.setTableName(tenantCode+"_BUSINESSACTIVITY");
                asyncLogService.saveBusinessBehavior(businessActivity);
            }
        }
    }

    @Override
    public String saveArchiveEnhance(String archiveCode, String archiveType,String fileMD5, String data) {
        String msg = archiveEnhanceService.saveArchiveEnhance(archiveCode,archiveType,fileMD5,data);
        return msg;
    }

    private final String extractPath(TenantCategory category,Long daId)
    {
        StringBuilder path = new StringBuilder().append(category.getFondsCode()).append(File.separator).append(category.getCode()).append(File.separator).
                append(daId).append(File.separator);
        return path.toString();
    }

    private String extractFilename(String type ,Long daId,int orderNo, String docFileType)
    {
        String fileName = daId+"0"+type+"A"+ (orderNo<999 ? (orderNo<99 ? (orderNo<9 ? "00"+orderNo:("0"+orderNo)):orderNo):orderNo);
        StringBuilder path = new StringBuilder().append(fileName).append(".").append(docFileType);
        return path.toString();
    }

    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
    {
        File desc = new File(uploadDir + File.separator + fileName);

        if (!desc.exists())
        {
            if (!desc.getParentFile().exists())
            {
                desc.getParentFile().mkdirs();
            }
        }
        return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
    }



    @Override
    public String saveOnlineArchive(String paketInfo) {
        logger.info("paketInfo={}",paketInfo);
        com.alibaba.fastjson.JSONArray array=com.alibaba.fastjson.JSONArray.parseArray(paketInfo);
        com.alibaba.fastjson.JSONArray success=new com.alibaba.fastjson.JSONArray(array.size());
        com.alibaba.fastjson.JSONArray fail=new com.alibaba.fastjson.JSONArray(array.size());
        com.alibaba.fastjson.JSONObject returnjson= new com.alibaba.fastjson.JSONObject(1<<1);
        for (int i = 0; i < array.size(); i++) {
            com.alibaba.fastjson.JSONObject json=new com.alibaba.fastjson.JSONObject();
            json= com.alibaba.fastjson.JSONObject.parseObject(array.get(i).toString());
            YqdaOnlineReception onlineReception=new YqdaOnlineReception();
            try{
                onlineReception.setName(json.getString("name"));
                onlineReception.setDescription(json.getString("description"));
                onlineReception.setDaCount(json.getInteger("daCount"));
                onlineReception.setCapacity(json.getString("capacity"));
                onlineReception.setType(json.getString("type"));
                onlineReception.setCarrier(json.getString("carrier"));
                onlineReception.setCarrierCount(json.getString("carrierCount"));
                onlineReception.setNd(json.getString("nd"));
                onlineReception.setDh(json.getString("dh"));
                onlineReception.setYjUnit(json.getString("yjUnit"));
                onlineReception.setJsUnit(json.getString("jsUnit"));
                onlineReception.setAppearance(json.getString("appearance"));
                onlineReception.setTrueExplain(json.getString("trueExplain"));
                onlineReception.setIntegrityExplain(json.getString("integrityExplain"));
                onlineReception.setUsableExplain(json.getString("usableExplain"));
                onlineReception.setSecureExplain(json.getString("secureExplain"));
                onlineReception.setCreateBy(json.getString("createBy"));
                onlineReception.setCreateTime(json.getString("createTime"));
                onlineReception.setAuditorBy(json.getString("auditorBy"));
                onlineReception.setUnitBy(json.getString("unitBy"));
                onlineReception.setUnitTime(json.getString("unitTime"));
                onlineReception.setAuditorTime(json.getString("auditorTime"));
                onlineReception.setIllustrate(json.getString("illustrate"));
                onlineReception.setWrittenBy(json.getString("writtenBy"));
                onlineReception.setWrittenTime(json.getString("writtenTime"));
                onlineReception.setCategoryId(json.getLong("categoryId"));
                onlineReception.setFilePath(json.getString("packetPath"));
                onlineReception.setOldTenantCode(json.getString("tenantCode"));
                ManageTenant manageTenant = manageService.selectTenantByManager("true");
                onlineReception.setTenantCode(manageTenant == null ? null:manageTenant.getTenantCode());
                onlineReception.setBiaoShi(json.getString("biaoShi"));
                onlineReception.setState(0);
                onlineReception.setReceptionTime(new Date());
                onlineReceptionService.insertOnlineReception(onlineReception);
                success.add(json.getString("biaoShi"));
            }catch (Exception e){
                fail.add(json.getString("biaoShi"));
                e.printStackTrace();
                continue;
            }
        }
        returnjson.put("success",success);
        returnjson.put("fail",fail);
        return returnjson.toString();
    }
}
